class Watcher{   //判断新值和旧值有没有变化
    constructor(vm,expr,cb){
        this.vm = vm,
        this.expr = expr,
        this.cb = cb,
        //先把旧值保存起来
        this.oldVal = this.getOldVal();
    }
    //取旧值
    getOldVal(){
        Dep.target = this;  //get的时候把这个watcher放入Dep中
        const oldVal = compileUtil.getVal(this.expr,this.vm)
        Dep.target = null;  //因为已经保存了 防止读取一次就放入一次的watcher
        return oldVal
    }
    //触发了dep的update后 通知update更新 此时的值为数据变化后的值
    update(){
        const newVal = compileUtil.getVal(this.expr,this.vm)
        if(newVal !== this.oldVal){
            this.cb(newVal)
        }
    }
}

class Dep{   //收集订阅者 通知
    constructor(){
        this.subs = [];
    }
    //收集观察者
    addSub(watcher){
        this.subs.push(watcher);
    }
    //通知观察者去更新
    notify(){
        console.log('通知Watcher更新',this.subs)
        this.subs.forEach(w=>w.update())
    }
}

class Observer{
    constructor(data){
        this.observe(data);
    }
    observe(data){
        //只考虑对象的情况
        if(data && typeof data === 'object'){
            Object.keys(data).forEach( key=>{
                this.defineReactive(data,key,data[key]);
            })
        }
    }
    defineReactive(obj,key,value){
        //递归遍历 value
        this.observe(value);
        const dep = new Dep();
        Object.defineProperty(obj,key,{
            enumerable:true,
            configurable:false,
            get(){
                //一开始编译时，用了哪个数据 就往Dep中添加Watcher
                Dep.target && dep.addSub(Dep.target)
                return value;
            },
            set:(newVal)=>{
                this.observe(newVal);
                if(newVal !== value){
                    value = newVal;
                }
                //告诉Dep通知变化
                dep.notify();
            }

        })
    }
}

// 数据劫持的数据是data里的数据
// 模板编译的数据是使用的数据 只有使用了的数据才有响应的watcher  watcher是在编译的时候产生的 并且被放到dep的subs中

//Dep是管理各个watcher的 使observer与watcher产生相对的关联

//同个数据的不同用法 会产生多个watcher 比如v-html用到了，v-model也用到了 就会产生两个watcher

//Dep 与 Watcher 是多对多的关系  
//因为Dep.target = this;使得Dep指向watcher的同时 也产生了不同的Dep
